package com.xiaode.controller.app.user;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Ret;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.redis.Cache;
import com.jfinal.plugin.redis.Redis;
import com.xiaode.common.UserTokenManager;
import com.xiaode.common.constant.Const;
import com.xiaode.common.model.Admin;
import com.xiaode.common.model.External;
import com.xiaode.common.model.OrgAdmin;
import com.xiaode.common.model.OrgClass;
import com.xiaode.common.model.Student;
import com.xiaode.common.model.UserAccount;
import com.xiaode.exce.EnumError;
import com.xiaode.util.ChatUtil;
import com.xiaode.util.SnowflakeIdWorker;
import com.xiaode.util.welink.WeLinkUtil;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

public class UserService {

	/**
	 * 修改密码
	 */
	public Ret modifyPassword(Integer accountId, String newPassword) throws Exception {
		UserAccount userAccount = UserAccount.dao.findById(accountId);
		newPassword = SecureUtil.md5(newPassword + userAccount.getId() + Const.salt);
		UserAccount ua = new UserAccount();
		ua.setId(accountId);
		ua.setPassword(newPassword);
		ua.update();
		return Ret.ok();
	}

	/**
	 * 上传头像
	 */
	public Ret importHead(Integer accountId, Integer userType, String head) {
		if (userType == Const.UserType.student) {
			Student student = Student.dao.findFirst("SELECT * FROM student WHERE accountId = ?", accountId);
			student.setAvatarUrl(head);
			student.update();
			
			Student o = Redis.use().get(Const.user.Student + student.getId());
	        o.setAvatarUrl(head);
	        Redis.use().set(Const.user.Student + student.getId(), o);
	        
			Redis.use().setex(Const.user.loginStudent + accountId, Const.user.timeToLiveSeconds, student);
            Redis.use().set(Const.user.Student + student.getId(), student);
		} else if (userType == Const.UserType.admin) {
			Admin admin = Admin.dao.findFirst("SELECT * FROM admin WHERE accountId = ?", accountId);
			admin.setAvatarUrl(head);
			admin.update();
			
			Admin o = Redis.use().get(Const.user.Admin + admin.getId());
	        o.setAvatarUrl(head);
	        Redis.use().set(Const.user.Admin + admin.getId(), o);
			
			Redis.use().setex(Const.user.loginAdmin + accountId, Const.user.timeToLiveSeconds, admin);
			Redis.use().set(Const.user.Admin + admin.getId(), admin);
		} else {
			Ret.fail().set("error", EnumError.USER_TYPE_NO.getObj());
		}
		return Ret.ok();
	}

	/**
	 * app用户和基座用户绑定 绑定成功后直接登录
	 */
	public Ret binDing(String account, String password, String banDingCode) throws Exception {
		UserAccount userAccount = UserAccount.dao.findFirst("SELECT * FROM user_account WHERE account = ? AND is_dele = 0 AND state = 1", account);
		if (BeanUtil.isEmpty(userAccount)) {
			return Ret.fail().set("error", EnumError.ACCOUNT_NO.getObj());
		}
		if (!StrUtil.equals(SecureUtil.md5(password + userAccount.getId() + Const.salt), userAccount.getPassword())) {
			return Ret.fail().set("error", EnumError.PASSWORD_ERROR.getObj());
		}
		// 是否已经绑定
		if (userAccount.getIsBindingPedestal()) {// 已经绑定
			return Ret.fail().set("error", EnumError.WELINK_HAVE_BINDING.getObj());
		}
		String wlUserId = Redis.use().get(Const.binDingCode + banDingCode);
		userAccount.setIsBindingPedestal(true);
		userAccount.setEduID(wlUserId);
		userAccount.update();
		Integer userType = userAccount.getUserType();
		if (userType == Const.UserType.admin) {
			Admin t = Admin.dao.findFirst("SELECT * FROM admin WHERE accountId = ?", userAccount.getId());
			Redis.use().zadd(Const.user.lastLoginTimeT,LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli(), t.getId());// 存最后登陆时间
			// 查询架构管理
			Set<Integer> frameworkPermission = frameworkPermission(t);
			t.put("frameworkPermission", frameworkPermission);
			List<Integer> clasList = OrgAdmin.dao.find("SELECT * FROM org_admin WHERE adminId = ? AND stratum = 3", t.getId()).stream().map(OrgAdmin::getStratumId).collect(Collectors.toList());
			t.put("clasIdList", clasList);
			//是否可以发布公告
			OrgAdmin oa = OrgAdmin.dao.findFirst("SELECT * FROM org_admin WHERE adminId = ? AND stratum = 2 AND (stratumId = 1 OR stratumId = 2 OR stratumId = 5)", t.getId());
			if(BeanUtil.isEmpty(oa)) {
				t.put("canAnnouncement", false);
			}else {
				t.put("canAnnouncement", true);
			}
			//所在最高层级
			Integer stratum = Db.queryInt("SELECT MIN(stratum) stratum  FROM org_admin WHERE adminId = ?", t.getId());
			t.put("stratum", stratum);
		}
		if (userType == Const.UserType.student) {
			Student s = Student.dao.findFirst("SELECT * FROM student WHERE accountId = ?", userAccount.getId());
			Redis.use().setex(Const.user.loginStudent + userAccount.getId(), Const.user.timeToLiveSeconds, s);
			Redis.use().zadd(Const.user.lastLoginTimeS,LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli(), s.getId());// 存最后登陆时间
			String userToken = UserTokenManager.generateToken(Kv.by("accountId", userAccount.getId()).set("userId", s.getId()).set("userType", Const.UserType.student).set("canLoginAdmin",userAccount.getCanLoginAdmin()).set("account", userAccount.getAccount()).toJson());
			Redis.use().setex("userToken:"+userToken, Const.user.timeToLiveSeconds, s.getId());
			return Ret.ok("user", s).set("token", userToken).set("usertype", Const.UserType.student);
		}
//		if(userType == 3) {
//			Parent p = Parent.dao.findFirst("SELECT * FROM parent WHERE accountId = ?", userAccount.getId());
//			Redis.use().setex(Const.user.loginParent + userAccount.getId(), Const.user.timeToLiveSeconds, p);
//			String userToken = UserTokenManager.generateToken(Kv.by("accountId", userAccount.getId()).set("userType", Const.UserType.admin).toJson());
//			return Ret.ok("user", p).set("token", userToken);
//		}
		return Ret.fail().set("error", EnumError.USER_TYPE_NO.getObj());
	}

	/**
	 * 用户登陆
	 */
	public Ret login(String account, String password, String code, Integer platform) throws Exception {

		UserAccount ua = null;
		if (platform == 2) {// 基座
			// 判断是否绑定
			if (StrUtil.isBlank(code)) {
				return Ret.fail().set("error", EnumError.NOT_HAVE_BASE_PARAM.getObj());
			}
			String wlUserId = WeLinkUtil.getWLUserId(code);
			if (StrUtil.isBlank(wlUserId)) {
				return Ret.fail().set("error", EnumError.BASE_LOGIN_FAIL.getObj());
			}
			ua = UserAccount.dao.findFirst("SELECT * FROM user_account WHERE eduID = ? AND is_dele = 0 AND state = 1", wlUserId);
			if (BeanUtil.isEmpty(ua)) {// 未绑定
				// 生成一个code
				String banDingCode = SnowflakeIdWorker.generateId().toString();
				Redis.use().setex(Const.binDingCode + banDingCode, Const.binDingCodeLiveSeconds, wlUserId);
				return Ret.ok("banDingCode", banDingCode);
			}
		} else if (platform == 1 || platform == 3) {// 需要账号密码
			if (StrUtil.isBlank(account) || StrUtil.isBlank(password)) {
				return Ret.fail().set("error", EnumError.ACCOUNT_PASSWORD_ERROR.getObj());
			}
			ua = UserAccount.dao.findFirst("SELECT * FROM user_account WHERE account = ? AND is_dele = 0 AND state = 1",account);
			if (BeanUtil.isEmpty(ua)) {
				return Ret.fail().set("error", EnumError.ACCOUNT_ERROR.getObj());
			}
			if (!StrUtil.equals(SecureUtil.md5(password + ua.getId() + Const.salt), ua.getPassword())) {
				return Ret.fail().set("error", EnumError.PASSWORD_ERROR.getObj());
			}
		} else {
			return Ret.fail().set("error", EnumError.PLATFORM_ERROR.getObj());
		}

		Integer userType = ua.getUserType();
		if (userType == Const.UserType.admin) {// 老师
			
			Admin t = Admin.dao.findFirst("SELECT * FROM admin WHERE accountId = ?", ua.getId());
			Redis.use().zadd(Const.user.lastLoginTimeT,LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli(), t.getId());// 存最后登陆时间
			// 查询架构管理
			Set<Integer> frameworkPermission = frameworkPermission(t);
			t.put("frameworkPermission", frameworkPermission);
			List<Integer> clasList = OrgAdmin.dao.find("SELECT * FROM org_admin WHERE adminId = ? AND stratum = 3", t.getId()).stream().map(OrgAdmin::getStratumId).collect(Collectors.toList());
			t.put("clasIdList", clasList);
			//是否可以发布公告
			OrgAdmin oa = OrgAdmin.dao.findFirst("SELECT * FROM org_admin WHERE adminId = ? AND stratum = 2 AND (stratumId = 1 OR stratumId = 2 OR stratumId = 5)", t.getId());
			if(BeanUtil.isEmpty(oa)) {
				t.put("canAnnouncement", false);
			}else {
				t.put("canAnnouncement", true);
			}
			//所在最高层级
			Integer stratum = Db.queryInt("SELECT MIN(stratum) stratum  FROM org_admin WHERE adminId = ?", t.getId());
			t.put("stratum", stratum);

			String userToken = UserTokenManager.generateToken(Kv.by("accountId", ua.getId()).set("userId", t.getId()).set("userType", Const.UserType.admin).set("canLoginAdmin",ua.getCanLoginAdmin()).set("account", ua.getAccount()).toJson());
			Redis.use().setex(Const.user.loginAdmin + ua.getId(), Const.user.timeToLiveSeconds, t);
			Redis.use().setex("userToken:"+userToken, Const.user.timeToLiveSeconds, ua.getId());//为了单点登录存了token
			
			return Ret.ok("user", t).set("token", userToken).set("usertype", Const.UserType.admin);
		
		} else if (userType == Const.UserType.student) {// 学生
			
			Student s = Student.dao.findFirst("SELECT * FROM student WHERE accountId = ?", ua.getId());
			if(BeanUtil.isEmpty(s)) {
				return Ret.fail().set("error", EnumError.USER_TYPE_NO.getObj());
			}
			Redis.use().setex(Const.user.loginStudent + ua.getId(), Const.user.timeToLiveSeconds, s);
			Redis.use().zadd(Const.user.lastLoginTimeS,LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli(), s.getId());// 存最后登陆时间
			String userToken = UserTokenManager.generateToken(Kv.by("accountId", ua.getId()).set("userId", s.getId()).set("userType", Const.UserType.student).set("canLoginAdmin",ua.getCanLoginAdmin()).set("account", ua.getAccount()).toJson());
			Redis.use().setex("userToken:"+userToken, Const.user.timeToLiveSeconds, ua.getId());//为了单点登录存了token
			return Ret.ok("user", s).set("token", userToken).set("usertype", Const.UserType.student);
		
		} else if (userType == Const.UserType.external) {//外部用户
			
			External external = External.dao.findFirst("SELECT * FROM external WHERE accountId = ?", ua.getId());
			if(BeanUtil.isEmpty(external)) {
				return Ret.fail().set("error", EnumError.USER_TYPE_NO.getObj());
			}
			Redis.use().setex(Const.user.loginExternal + ua.getId(), Const.user.timeToLiveSeconds, external);
			Redis.use().zadd(Const.user.lastLoginTimeE,LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli(), external.getId());// 存最后登陆时间		
			String userToken = UserTokenManager.generateToken(Kv.by("accountId", ua.getId()).set("userId", external.getId()).set("userType", Const.UserType.external).set("canLoginAdmin", false).set("account", ua.getAccount()).toJson());
			Redis.use().setex("userToken:"+userToken, Const.user.timeToLiveSeconds, ua.getId());//为了单点登录存了token
			return Ret.ok("user", external).set("token", userToken).set("usertype", Const.UserType.external);
		
		} else {
			return Ret.fail().set("error", EnumError.USER_TYPE_NO.getObj());
		}
	}

	/**
	 * 获取聊天token
	 */
	public Ret getWsToken(Integer accountId) throws Exception {
		// 发送聊天系统请求
		String res = ChatUtil.getClientToken(accountId);
		String wsToken = JSONUtil.parseObj(res).getStr("wsToken");
		return Ret.ok("wsToken", wsToken);
	}
	
	public Ret getMeInfo(Integer accountId, Integer userType) {
		if (userType == Const.UserType.admin) {// 老师
			Admin a = Redis.use().get(Const.user.loginAdmin + accountId);
			return Ret.ok("user", a);
		} else if (userType == Const.UserType.student) {// 学生
			Student s = Redis.use().get(Const.user.loginStudent + accountId);
			//额外添加人脸状态
			Integer faceState = Db.queryInt("SELECT face_state FROM user_account WHERE id = ?", s.getAccountId());
			s.put("faceState", faceState);
			return Ret.ok("user", s);
		} else {
			return Ret.fail().set("error", EnumError.USER_TYPE_NO.getObj());
		}
	}

	/**
	 * 查询用户的信息
	 */
	public Ret findUserInfo(Integer accountId) throws Exception {
		List<Student> students;
		List<Admin> admins;
		if (accountId == null) {
			students = Student.dao.find("SELECT id,sex,avatarUrl,number,name,clasId,accountId,user_type userType FROM student WHERE isDele = 0");
			admins = Admin.dao.find("SELECT id,gender sex,avatarUrl,accountId,name,healther_teacher,user_type userType FROM admin WHERE user_type = 1 AND isDele = 0");
		} else {
			students = Student.dao.find("SELECT id,sex,avatarUrl,number,name,clasId,accountId,user_type userType FROM student WHERE accountId = ? AND isDele = 0",accountId);
			admins = Admin.dao.find("SELECT id,gender sex,avatarUrl,accountId,name,healther_teacher,user_type userType FROM admin WHERE accountId = ? AND user_type = 1 AND isDele = 0",accountId);
		}
		Map<Integer, Student> studentMap = students.stream().collect(Collectors.toMap(Student::getAccountId, student -> student));
		Map<Integer, Admin> adminMap = admins.stream().collect(Collectors.toMap(Admin::getAccountId, admin -> admin));
		return Ret.ok().set("students", studentMap).set("admins", adminMap);
	}

	/**
	 * 查询用户详情页
	 */
	public Ret findUserDetails(Integer accountId) {
		Cache redis = Redis.use();
		Record record = redis.hget(Const.user.AccountIdInfo, accountId);
		if (BeanUtil.isEmpty(record)) {
			return Ret.fail().set("error", EnumError.USER_NULL.getObj());
		}
		Ret returnData = Ret.ok();
		returnData.set("idInfo", record);
		Integer userType = record.getInt("userType");
		if (userType == Const.UserType.student) {
			Record student = Db.findFirst("SELECT studentNo,name,zScore,avatarUrl,sex,user_type userType,id FROM student WHERE accountId = ?", accountId);
			if (BeanUtil.isEmpty(student)) {
				return Ret.fail().set("error", EnumError.USER_NULL.getObj());
			}
			returnData.set("student", student);
			// 月度之星数
			Integer starCount = Db.queryInt("SELECT count(*) FROM month_star WHERE studentId = ? AND `rank` < 4 AND score > 0", student.getInt("id"));//排名前三的
			returnData.set("starCount", starCount);
			// 推荐数
			Integer recommendCount = Db.queryInt("SELECT count(*) FROM campus_share_teacher_recommend WHERE create_account_id = ? ", accountId);
			returnData.set("recommendCount", recommendCount);
			// 轨迹数
			Integer trajectoryCount = Db.queryInt("SELECT count(*) FROM student_trajectory WHERE user_account_id = ?", accountId);
			returnData.set("trajectoryCount", trajectoryCount);
			// 勋章
			List<Record> medalList = Db.find("SELECT * FROM medal_user WHERE account_id = ?", accountId);
			returnData.set("medalList", medalList);
		} else if (userType == Const.UserType.admin) {
			Admin admin = Admin.dao.findFirst("SELECT * FROM admin WHERE accountId = ?", accountId);
			if (BeanUtil.isEmpty(admin)) {
				return Ret.fail().set("error", EnumError.USER_NULL.getObj());
			}
			returnData.set("admin", admin);
		}
		return returnData;
	}

	
	

	

	public static Set<Integer> frameworkPermission(Admin admin) {
		List<OrgAdmin> orgAdmins = OrgAdmin.dao.find("SELECT stratum,adminId,stratumId FROM org_admin WHERE adminId = ?", admin.getId());
		HashSet<Integer> hashSet = new HashSet<>();
		for (OrgAdmin orgAdmin : orgAdmins) {
			Integer stratum = orgAdmin.getStratum();
			if (stratum == 1) {
				List<OrgClass> orgClass = OrgClass.dao.find("SELECT id FROM org_class");
				Set<Integer> collect = orgClass.stream().map(orgClass1 -> orgClass1.getId()).collect(Collectors.toSet());
				hashSet.addAll(collect);
				break;
			} else if (stratum == 2) {
				List<OrgClass> orgClasses = OrgClass.dao.find("SELECT id FROM org_class WHERE adminGradeId = ?",orgAdmin.getStratumId());
				Set<Integer> collect = orgClasses.stream().map(orgClass -> orgClass.getId()).collect(Collectors.toSet());
				hashSet.addAll(collect);
			} else {
				OrgClass orgClass = OrgClass.dao.findById(orgAdmin.getStratumId());
				if (orgClass != null) {
					hashSet.add(orgClass.getId());
				}
			}
		}
		return hashSet;
	}
	
	/**
	 * 学生获取家长绑定二维码
	 */
	public Ret getParentBinDingCode(Integer studentId, Integer userType) {
		if(userType != Const.UserType.student) {
			return Ret.fail().set("error", EnumError.USER_TYPE_NO.getObj());
		}
		Set<String> codeKeys = Redis.use().keys(Const.user.ParentBinDingCode + studentId + ":*");
		if(codeKeys.size() > 0) {
			String codeKey = codeKeys.iterator().next();
			String code = codeKey.split(":")[2];
			return Ret.ok("qrCode", code);
		}
		long c = System.currentTimeMillis();
		Redis.use().setex(Const.user.ParentBinDingCode + studentId + ":" + c, 1800L, studentId);
		return Ret.ok("qrCode", c);
	}
	
	
	

	public static void main(String[] args) {
		System.out.println(SecureUtil.md5(SecureUtil.md5("111111") + "7688" + Const.salt));  
		System.out.println(SecureUtil.md5(SecureUtil.md5("111111") + "7689" + Const.salt));  
		System.out.println(SecureUtil.md5(SecureUtil.md5("111111") + "7690" + Const.salt));  
		System.out.println(SecureUtil.md5(SecureUtil.md5("111111") + "7691" + Const.salt));  
		System.out.println(SecureUtil.md5(SecureUtil.md5("111111") + "7692" + Const.salt));  
	}
}
